#pragma once
#include <map>
#include "mysql_connection.h"
#include "mysql_driver.h"
#include "cppconn/exception.h"
#include "cppconn/driver.h"
#include "cppconn/connection.h"
#include "cppconn/resultset.h"
#include "cppconn/prepared_statement.h"
#include "cppconn/statement.h"
#include <string>
#include "singleton.h"
#include <queue>
#include "object_pool.h"

class MysqlStmtPrepare
{
public:
	MysqlStmtPrepare(const std::string& sql, sql::PreparedStatement * _prep)
		:_prep(_prep)
		,_sql(sql)
	{}
	~MysqlStmtPrepare()
	{
		if (_prep != nullptr)
		{
			delete _prep;
		}
	}
public:
	sql::PreparedStatement *		_prep;
	std::string				_sql;
};

class GameMysql
{
public:
	bool initMysql(std::string url, int port, std::string username, std::string password);
	inline sql::Connection * GetConnect()
	{
		if (connection_->isClosed())
		{
			Reconnect();
		}
		return connection_;
	}
	sql::PreparedStatement* GetPrepare(const std::string& sql);
	~GameMysql()
	{
		ClearPrep();
	}
protected:
	bool Reconnect();
	sql::Connection * Connect();
	void ClearPrep();
private:
	std::map<std::string, MysqlStmtPrepare*>		_prepare_list;
	sql::Driver * driver_;
	sql::Connection * connection_;
	std::string  username_;
	std::string  password_;
	std::string  url_;
	int port_;
};

class GameMysql_MasterSlave
{
public:
	GameMysql _master;
	GameMysql _slave;
public:
	bool initMysql(std::string url, int port, std::string username, std::string password, bool is_master)
	{
		if (is_master)
		{
			return _master.initMysql(url, port, username, password);
		}
		else
		{
			return _slave.initMysql(url, port, username, password);
		}
	}
	inline sql::Connection * GetConnect(bool is_master = true)
	{
		if (is_master)
		{
			return _master.GetConnect();
		}
		else
		{
			return _slave.GetConnect();
		}
	}
};

#define MYSQL_CONN Singleton<GameMysql>::Instance()

#define P_MYSQL_POOL Singleton<ObjectPool<GameMysql>>::Instance()
#define MYSQL_POOL (*Singleton<ObjectPool<GameMysql>>::Instance())

#define MYSQL_POOL_CONN SmartObject<GameMysql>(Singleton<ObjectPool<GameMysql>>::Instance())